Day-19中我們提到了Pod, ReplicaSet與Deployment,也知道了如何將我們的containers轉換成Pod,利用並共享同個Pod的資源。但截至目前為止的我們所學都只局限在Pod的自身,我們尚未知道Pod與Pod之間如何溝通,也不清楚外界如何將request送至我們叢集內部的Pod當中。
這些問題都會在未來兩章節中解答!
簡單來說Service就是通往Pod的通道,在撰寫Service時需要透過labels指定Service所Mapping的對象,當Service收到requests時,會將request redirect到有這個labels的Pod當中。
因為Pods的數量是不固定的,而且每有Pod被新建或刪除,它們的IP都會改變。但有了Service的存在,我們只要把requests送至Service,他就會自動幫我們做負載平衡並將requests送至Pod當中。
所以
在Service中有著三個不同的port對應著不同的接口,分別是NodePort、Port以及TargetPort。並對接著不同的IP,External IP、Cluster IP與Pod IP
會透過service進行其他pod服務存取的使用者有兩者,分別為k8s集群外部使用者與集群內部的其他pod,儘管兩者想存取的路徑都相同,但仍然存在著一個關鍵差異在於: 存取ip不同。
裸露的網路位址,供外部使用者存取。對應到service上的nodePort。
<EXTERNAL-IP>:<nodePort>
叢集內部的網路位址,供內部使用者存取。對應到service上的port。Cluster IP為虛擬靜態IP,當物件被產生時,會一併產生Cluster IP並且在物件被刪除前不在改變。
<CLUSTER-IP>:<port>
每個pod獨有的網路位址,只有叢集內可以連線。對應到service上的targetPort。
<targetPort>
那這邊我們一樣,寫一個對接ClusterIP的Service,後面在來解析這個yaml。
kind: Service
apiVersion: v1
metadata:
name: ironman
labels:
app: ironman
spec:
type: ClusterIP
ports:
- name: ironman
protocol: TCP
port: 80
targetPort: 80
selector:
app: ironman
$ kubectl apply -f service.yaml
service/ironman created
$ kubectl get service ironman
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ironman ClusterIP 10.4.10.250 <none> 80/TCP 45s
apiVersion 是代表目前 Kubernetes 中該元件的版本號。以上述的例子 Pod 是 v1,而 v1也是目前Kubernetes中核心的版本號。在日後也會陸續看到 betav1, v1alpha1 等版本號,更多 Kubernetes API 的版本號,可至 官網 API versioning查看。
描述該物件的屬性,常見屬性有Pod、Node、Service、Namespace、ReplicationController....etc
在 metadata 中,有三個重要的 Key,分別是 name, labels, annotations。
我們可以在 metadata.name 的欄位指定這個 Pod 的名稱,這裡 Pod 的名稱就是 my-pod
metadata.labels 是 Kubernetes 的是核心的元件之一,Kubernetes 會透過 Label Selector 將Pod分群管理。
annotations 的功能與 labels 相似。相較於labels,annotations 通常是使用者任意自定義的附加資訊,提供外部進行查詢使用,像是版本號,發布日期等等。
可以指定Service的型別,可以是ClusterIP type(default)、NodePort與LoadBalancer。
可以指定,創建的Service的Cluster IP(for 內部使用者),是哪個port number去對應到targetPort
可以指定,創建的Service的External IP(for 外部使用者),是哪個port number去對應到nodePort。
另外,Service可以指定的nodePort只有30000~32767
targetPort很好理解,targetPort是pod上的端口,從port與nodePort進來的requests,最終會經由kube-proxy流入後端pod的targetPort上進入容器。
目前service僅支援TCP與UDP兩種protocol,預設為TCP
selector會幫我們將特定port number收到的流量去導向標籤app為該標籤的pod。
Ipvs是一個用於負載平衡的Linux kernal features。
每個在kubernetes的pod或是service在創建時,都會在一個名為kube-dns的pod當中記錄每個pod/service所mapping到的dns,而該dns的name是自動創建的。因此在內部kubernetes cluster當中,pod與pod之間的溝通可以透過該dns連到所需溝通之pod的service dns。
<service_name>..svc.cluster.local
我們先藉由commnad來看一下dns
$ **kubectl exec -it ironman-6d655d444d-jwf4b -c ironman bash 3010 14:33:48
$ cat /etc/resolv.conf
nameserver 10.4.0.10
search default.svc.cluster.local svc.cluster.local cluster.local asia-east1-a.c.oval-compass-290412.internal c.oval-compass-290412.internal google.internal
options ndots:5**
這邊的default.svc.cluster.local就是dns的postfix
我們先建立一個臨時的curl pod。
$ kubectl run --rm --generator=run-pod/v1 curl --image=radial/busyboxplus:curl -i --tty
那我們再來就GET看看上面所建立的service ironman吧
$ curl -X GET http://ironman.default.svc.cluster.local:80/v1/hc
{"message": "This endpoint for web service health check"}
那到這邊我們就確定kube-dns確實能work了,之後cluster內部的轉發也能全部透過kube-dns來實現。
本篇章所有程式碼將放在下面的github project當中的branch day-21
https://github.com/Neskem/ironman_2020/tree/day-21
這邊我們學習了如何撰寫cluster IP的service,並且也學習了kube-proxy的原理與kube-dns的運用,這也讓我們在叢集內部的流量遞送更如虎添翼。那在下個章節我們會學習如何透過loadbalancer與ingress從外部與Pod進行溝通。
https://kubernetes.io/docs/concepts/services-networking/service/